/* 
 * File:   SimpleNumber.cpp
 * Author: Gab'z
 * 
 * Created on 29 mai 2012, 12:25
 */

#include "SimpleNumber.h"
#include "Integer.h"
#include "Rationnal.h"
#include "Real.h"

namespace calculator {

    SimpleNumber::SimpleNumber() : Number() {
    }

    SimpleNumber::~SimpleNumber() {
    }

    SimpleNumber* add(const SimpleNumber* n1, const SimpleNumber* n2) throw (ArithmeticException) {
        const Integer* p_integer1 = dynamic_cast<const Integer*> (n1);
        const Integer* p_integer2 = dynamic_cast<const Integer*> (n2);
        const Rationnal* p_rationnal1 = dynamic_cast<const Rationnal*> (n1);
        const Rationnal* p_rationnal2 = dynamic_cast<const Rationnal*> (n2);
        const Real* p_real1 = dynamic_cast<const Real*> (n1);
        const Real* p_real2 = dynamic_cast<const Real*> (n2);
        try {
            if ((p_real1 != 0) || (p_real2 != 0)) return new Real(*n1 + *n2);
            else if ((p_rationnal1 != 0) || (p_rationnal2 != 0)) return new Rationnal(*n1 + *n2);
            else if ((p_integer1 != 0) && (p_integer2 != 0)) return new Integer(*n1 + *n2);
        } catch (ArithmeticException& e) {
            throw;
        }
        throw ArithmeticException("SimpleNumber addition error");
    }

    SimpleNumber* sub(const SimpleNumber* n1, const SimpleNumber* n2) throw (ArithmeticException) {
        const Integer* p_integer1 = dynamic_cast<const Integer*> (n1);
        const Integer* p_integer2 = dynamic_cast<const Integer*> (n2);
        const Rationnal* p_rationnal1 = dynamic_cast<const Rationnal*> (n1);
        const Rationnal* p_rationnal2 = dynamic_cast<const Rationnal*> (n2);
        const Real* p_real1 = dynamic_cast<const Real*> (n1);
        const Real* p_real2 = dynamic_cast<const Real*> (n2);
        try {
            if ((p_real1 != 0) || (p_real2 != 0)) return new Real(*n1 - *n2);
            else if ((p_rationnal1 != 0) || (p_rationnal2 != 0)) return new Rationnal(*n1 - *n2);
            else if ((p_integer1 != 0) && (p_integer2 != 0)) return new Integer(*n1 - *n2);
        } catch (ArithmeticException& e) {
            throw;
        }
        throw ArithmeticException("SimpleNumber substraction error");
    }

    SimpleNumber* mul(const SimpleNumber* n1, const SimpleNumber* n2) throw (ArithmeticException) {
        const Integer* p_integer1 = dynamic_cast<const Integer*> (n1);
        const Integer* p_integer2 = dynamic_cast<const Integer*> (n2);
        const Rationnal* p_rationnal1 = dynamic_cast<const Rationnal*> (n1);
        const Rationnal* p_rationnal2 = dynamic_cast<const Rationnal*> (n2);
        const Real* p_real1 = dynamic_cast<const Real*> (n1);
        const Real* p_real2 = dynamic_cast<const Real*> (n2);
        try {
            if ((p_real1 != 0) || (p_real2 != 0)) return new Real(*n1 * *n2);
            else if ((p_rationnal1 != 0) || (p_rationnal2 != 0)) return new Rationnal(*n1 * *n2);
            else if ((p_integer1 != 0) && (p_integer2 != 0)) return new Integer(*n1 * *n2);
        } catch (ArithmeticException& e) {
            throw;
        }
        throw ArithmeticException("SimpleNumber multiplication error");
    }

    SimpleNumber* div(const SimpleNumber* n1, const SimpleNumber* n2) throw (ArithmeticException) {
        const Integer* p_integer1 = dynamic_cast<const Integer*> (n1);
        const Integer* p_integer2 = dynamic_cast<const Integer*> (n2);
        const Rationnal* p_rationnal1 = dynamic_cast<const Rationnal*> (n1);
        const Rationnal* p_rationnal2 = dynamic_cast<const Rationnal*> (n2);
        const Real* p_real1 = dynamic_cast<const Real*> (n1);
        const Real* p_real2 = dynamic_cast<const Real*> (n2);
        try {
            if ((p_real1 != 0) || (p_real2 != 0)) return new Real(*n1 / *n2);
            else if ((p_rationnal1 != 0) || (p_rationnal2 != 0)) return new Rationnal(*n1 / *n2);
            else if ((p_integer1 != 0) && (p_integer2 != 0)) return new Integer(*n1 / *n2);
        } catch (ArithmeticException& e) {
            throw;
        }
        throw ArithmeticException("SimpleNumber division error");
    }

    SimpleNumber* pow(const SimpleNumber* sn1, const SimpleNumber* sn2) throw (ArithmeticException) {
        const Integer* p_integer1 = dynamic_cast<const Integer*> (sn1);
        const Rationnal* p_rationnal1 = dynamic_cast<const Rationnal*> (sn1);
        const Real* p_real1 = dynamic_cast<const Real*> (sn1);
        const Integer* p_integer2 = dynamic_cast<const Integer*> (sn2);
        try {
            if (p_integer1 != 0 && p_integer2 != 0) {
                if (p_integer2->value() >= 0) {
                    Integer e = Integer(*p_integer1);
                    e.pow((unsigned int) p_integer2->value());
                    return new Integer(e);
                } else {
                    Real r = Real(*p_integer1);
                    r.pow(*sn2);
                    return new Real(r);
                }
            } else if (p_rationnal1 != 0 || p_integer2 != 0) {
                Rationnal r = Rationnal(*p_rationnal1);
                r.pow(*p_integer2);
                return new Rationnal(r);
            } else {
                Real r = Real(*p_real1);
                r.pow(*sn2);
                return new Real(r);
            }
        } catch (ArithmeticException& e) {
            throw;
        }
        throw ArithmeticException("SimpleNumber pow error");
    }

}
